#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h> 
#include <sys/msg.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>


#include "proto1.h"

static key_t key;
static int msgid;

enum
{
	STATE_P=1,
	STATE_D,
	STATE_Err,
	STATE_DOT,
	STATE_Ex,
	STATE_T
};

struct snddir_st
{
	int state;
	char * spath;
	char * errstr;
	int fd;
	off_t offset;
	int _errno_;
	union msg_s2c_un msg_s2c;
};

/*
 *发送文件地址
 * */
void sndPath(struct snddir_st * snddir)
{
	msg_path_t msg_path;
	msg_path.mtype=MSG_PATH;
	strcpy(msg_path.path,snddir->spath);
//	printf("path==%s\n",msg_path.path);	
	if(msgsnd(msgid,&msg_path,sizeof(msg_path)-sizeof(long),0)<0)
	{
		snddir->state=STATE_Ex;
		snddir->errstr="msgsnd()";
		snddir->_errno_=errno;
	}
	else
	{
		snddir->state=STATE_D;
		int fd=0;
		while((fd=open("tmp",O_WRONLY|O_CREAT|O_TRUNC,0600))<0)
		{
			if(errno!=EINTR)
			{
				snddir->state=STATE_Ex;
				snddir->errstr="open()";
				snddir->_errno_=errno;
				break;
			}
		}
		if(fd>0)
		{
			snddir->fd=fd;
		}
	}
}

/*
 *接收数据
 * */
void rcvData(struct snddir_st * snddir)
{
//	snddir->state=STATE_D;
	union msg_s2c_un msg_s2c;
	if(msgrcv(msgid,&msg_s2c,sizeof(msg_s2c)-sizeof(long),0,0)<0)
	{
		snddir->state = STATE_Ex;
		snddir->_errno_ = errno;
		snddir->errstr = "rcvData msgrcv()";
		return;
	}
	snddir->state = msg_s2c.mtype;
	printf("mtype==%d\n",msg_s2c.mtype);
	snddir->msg_s2c = msg_s2c;
	if(snddir->state==MSG_DATA)
	{
		//write
		int ret=0;
		int pos=0;
		printf("len==%d\n",msg_s2c.datamsg.datalen);
		while(msg_s2c.datamsg.datalen>0)
		{
			ret=write(snddir->fd,msg_s2c.datamsg.data+pos,msg_s2c.datamsg.datalen);
			if(ret<0)
			{
				if(errno!=EINTR)
				{
					snddir->state = STATE_Ex;
					snddir->_errno_=errno;
					snddir->errstr = "writer()";
					close(snddir->fd);
				}
				else
					continue;
			}
			pos+=ret;
			msg_s2c.datamsg.datalen-=ret;
		}
	}
}

/*
 *打印服务短报错
 * */
void rcvErr(struct snddir_st * snddir)
{
	snddir->state=STATE_Ex;
	//perror(snddir->msg_s2c.errmsg._errno_);
	fprintf(stdout,"%s\n",strerror(snddir->msg_s2c.errmsg._errno_));
	fflush(NULL);
}

void rcvDOT(struct snddir_st * snddir)
{
	snddir->state=STATE_T;
	close(snddir->fd);
}

void snd_diver(struct snddir_st * snddir)
{
	switch(snddir->state)
	{
		case STATE_P:
			sndPath(snddir);
			break;
		case STATE_D:
			rcvData(snddir);
			break;
		case STATE_DOT:
			rcvDOT(snddir);
			break;
		case STATE_Err:
			rcvErr(snddir);
			break;
		case STATE_Ex:
			perror(snddir->errstr);
			snddir->state = STATE_T;
			break;
		case STATE_T:
			exit(1);
			break;
		default:
			break;
	}
}

int main(int argc ,char **argv)
{
	if(argc!=2)
	{
		fprintf(stderr,"Usage..\n");
		exit(1);
	}
	struct snddir_st  snd;
	snd.state=STATE_P;
	snd.spath=argv[1];
	snd.fd=-1;
	key = ftok(KEYPATH,KEYPROJ);
	if(key<0)
	{
		snd.state=STATE_Ex;
		snd.errstr="ftok()";
	}
	msgid=msgget(key,0);
	if(msgid<0)
	{
		snd.state=STATE_Ex;
		snd.errstr="msgget()";
	}
	//sndPath(snddir);
	//snd_diver(&snd);
	while(1)
	{
		snd_diver(&snd);
	}
	exit(0);
}
